#include "EPollPoller.h"

// Channel未添加到Poller中
const int kNew = -1;  // channel的成员index_ = -1
// Channel已添加到Poller中
const int kAdded = 1;
// Channel从Poller中删除
const int kDeleted = 2;

EPollPoller::EPollPoller(EventLoop* loop)
    : Poller(loop)
    , epollfd_(::epoll_create1(EPOLL_CLOEXEC))
    , events_(kInitEventListSize)
{
    if(epollfd_ < 0)
    {
        LOG_FATAL("epoll_create1 error:%d %s\n", errno, strerror(errno));
    }
}

EPollPoller::~EPollPoller()
{
    ::close(epollfd_);
}

// epoll_wait等待事件的发生，如果有事件发生，会将其填入到activeChannels中
Timestamp EPollPoller::poll(int timeoutMs, ChannelList* activeChannels)
{
    LOG_DEBUG("function: %s, fd total count:%d\n", __FUNCTION__, activeChannels.size());

    int numEvents = ::epoll_wait(epollfd_, &*events_.begin(), static_cast<int>(events_.size()), timeoutMs);
    int saveErrno = errno;
    Timestamp now(Timestamp::now());

    if(numEvents > 0)
    {
        LOG_DEBUG("%d events happened \n", numEvents);
        fillActiveChannels(numEvents, activeChannels);
        if (numEvents == events_.size())
        {
            events_.resize(events_.size() * 2); // 扩容
        }
    }
    else if(numEvents == 0)
    {
        LOG_DEBUG("%s nothing happened\n", __FUNCTION__);
    }
    else
    {
        if(saveErrno != errno)
        {
            errno = saveErrno;
            LOG_ERROR("EPollPoller::poll error:%d %s\n", errno, strerror(errno));
        }
    }

    return now;
}

// 填写活跃的连接
void EPollPoller::fillActiveChannels(int numEvents, ChannelList* activeChannels) const
{
    for (int i = 0; i < numEvents; ++i)
    {
        Channel* channel = static_cast<Channel*>(events_[i].data.ptr);
        channel->set_revents(events_[i].events);
        // EventLoop就拿到了它的Poller给它返回的所有发生事件的channel列表了
        activeChannels->push_back(channel); 
    }
}

// Channel调用的update和remove，都是调用EventLoop的updateChannel和removeChannel
// 而EventLoop都是调用Poller的updateChannel和removeChannel，因为EventLoop是包含
// Channel和Poller的
void EPollPoller::updateChannel(Channel* channel)
{
    const int index = channel->index(); // 获取Channel在Poller中的状态
    LOG_INFO("function: %s, fd: %d, events: %d, index: %d\n", __FUNCTION__, channel->fd(), channel->events(), index);

    if(index == kNew || index == kDeleted)
    {
        if(index == kNew)
        {
            int fd = channel->fd();
            channels_[fd] = channel;
        }

        channel->set_index(kAdded);
        update(EPOLL_CTL_ADD, channel);
    }
    else // Channel已经在Poller上注册过了
    {
        int fd = channel->fd();
        if(channel->isNoneEvent())
        {
            update(EPOLL_CTL_DEL, channel);
            channel->set_index(kDeleted);
        }
        else
        {
            update(EPOLL_CTL_MOD, channel);
        }
    }
}

// 从Poller中删除Channel
void EPollPoller::removeChannel(Channel* channel)
{
    int fd = channel->fd();
    channels_.erase(fd);

    LOG_INFO("function: %s, fd: %d\n", __FUNCTION__, fd);

    int index = channel->index();
    if(index == kAdded)
    {
        update(EPOLL_CTL_DEL, channel);
    }
    channel->set_index(kDeleted);
}

// 更新Channel通道：add / del / mod
void EPollPoller::update(int operation, Channel* channel)
{
    struct epoll_event event;
    bzero(&event, sizeof event);

    int fd = channel->fd();
    event.events = channel->events();
    event.data.ptr = channel;

    if(::epoll_ctl(epollfd_, operation, fd, &event) < 0)
    {
        if(operation == EPOLL_CTL_DEL)
        {
            LOG_ERROR("epoll_ctl del error:%d %s", errno, strerror(errno));
        }
        else
        {
            LOG_FATAL("epoll_ctl add/mod error:%d %s", errno, strerror(errno));
        }
    }
}